package com.yzjs.common;

import com.google.common.base.CaseFormat;
import com.yzjs.common.base.entity.column.CodeMakerCfg;
import com.yzjs.common.base.entity.column.ColumnEntity;
import com.yzjs.common.base.entity.column.TableEntity;
import com.yzjs.common.exception.RRException;
import com.yzjs.common.util.FileUtil;
import com.yzjs.common.util.conversion.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.lang.StringUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

import java.io.File;
import java.io.StringWriter;
import java.util.*;

@Slf4j
public class GenUtils {





    /**
     *
     * @param cfgUser    用户配置信息
     * @param tableEntity
     * @param columns
     */
    public static void generatorCode(CodeMakerCfg cfgUser, TableEntity tableEntity,
                                     List<Map<String, String>> columns) {

        boolean hasBigDecimal = false;
        //系统配置配置信息
        Configuration config = getConfig();

        //表名转换成Java类名
        String className = tableToJava(tableEntity.getTableName(), null);
        tableEntity.setClassName(className);
        tableEntity.setClassname(StringUtils.uncapitalize(className));

        //列信息
        List<ColumnEntity> columsList = new ArrayList<>();
        for(Map<String, String> column : columns){
            ColumnEntity columnEntity = new ColumnEntity();
//            columnEntity.setColumnName(column.get("COLUMNNAME" ));
//            columnEntity.setDataType(column.get("DATATYPE" ));
//            columnEntity.setComments(column.get("COLUMNCOMMENT" ));
            columnEntity.setExtra(column.get("EXTRA" ));
            columnEntity.setColumnName(column.get("columnName" ));
            columnEntity.setDataType(column.get("dataType" ));
            columnEntity.setComments(column.get("columnComment" ));



            //列名转换成Java属性名
            String attrName = columnToJava(columnEntity.getColumnName());
            columnEntity.setAttrName(attrName);
            columnEntity.setAttrname(StringUtils.uncapitalize(attrName));

            //列的数据类型，转换成Java类型
            String attrType = config.getString(columnEntity.getDataType(), "unknowType" );
            columnEntity.setAttrType(attrType);
            if (!hasBigDecimal && attrType.equals("BigDecimal" )) {
                hasBigDecimal = true;
            }
            //是否主键
            if ("PRI".equalsIgnoreCase(column.get("columnKey" )) && tableEntity.getPk() == null) {
                tableEntity.setPk(columnEntity);
            }
            columsList.add(columnEntity);
        }
        tableEntity.setColumns(columsList);

        //没主键，则第一个字段为主键
        if (tableEntity.getPk() == null) {
            tableEntity.setPk(tableEntity.getColumns().get(0));
        }


        //设置velocity资源加载器
        Properties prop = new Properties();
        prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader" );
        Velocity.init(prop);
        String mainPath = config.getString("mainPath" );
        //封装模板数据
        Map<String, Object> map = new HashMap<>();
        map.put("tableName", tableEntity.getTableName());
        map.put("comments", tableEntity.getTableComment());

        map.put("pk", tableEntity.getPk());
        map.put("className", tableEntity.getClassName());
        map.put("classname", tableEntity.getClassname());
        map.put("pathName", tableEntity.getClassname().toLowerCase());
        map.put("columns", tableEntity.getColumns());
        map.put("hasBigDecimal", hasBigDecimal);
        map.put("mainPath", mainPath);
        map.put("notGenerateFields",cfgUser.getNotGenerateFields());

        map.put("package", cfgUser.getModlePackage() );
        map.put("serverName", cfgUser.getServerName() );

        map.put("moduleName", tableEntity.getClassname() );
        map.put("author", cfgUser.getAutherName());
        map.put("email", config.getString("email" ));
        map.put("datetime", DateUtils.formatDateTime());
        VelocityContext context = new VelocityContext(map);

        //获取模板列表
        List<String> templates = getTemplates();
        for (String template : templates) {
            //渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, "UTF-8");
            tpl.merge(context, sw);
            String fileName = getFileName(template, tableEntity.getClassName(), cfgUser.getModlePackage(), tableEntity.getClassname() );
            fileName = System.getProperty("user.dir")+ File.separator +"src"+ File.separator+ fileName ;
            File file =  new File(fileName);
            if(file.exists()){
                log.info(  "文件已存在,不需要再次生成  " + fileName);
            }else{
                log.info(  "文件开始生成 "+fileName);
                FileUtil.writeTxtFile(sw.toString(),file, "utf-8");
                log.info(  "文件开始生成完毕 "+fileName);

            }


        }
    }





    public static List<String> getTemplates(){
        List<String> templates = new ArrayList<String>();
        templates.add("template/Entity.java.vm");
        templates.add("template/Mapper.java.vm");
        templates.add("template/Mapper.xml.vm");
        templates.add("template/Service.java.vm");
        templates.add("template/ServiceImpl.java.vm");
        templates.add("template/Controller.java.vm");
       // templates.add("template/menu.sql.vm");

       // templates.add("template/index.vue.vm");
        // templates.add("template/add-or-update.vue.vm");

        return templates;
    }

    /**
     * 获取配置信息
     */
    public static Configuration getConfig() {
        try {
            return new PropertiesConfiguration("generator.properties" );
        } catch (ConfigurationException e) {
            throw new RRException("获取配置文件失败，", e);
        }
    }


    /**
     * 表名转换成Java类名
     */
    public static String tableToJava(String tableName, String[] tablePrefixArray) {
        if(null != tablePrefixArray && tablePrefixArray.length>0){
            for(String tablePrefix : tablePrefixArray){
                tableName = tableName.replace(tablePrefix, "");
            }
        }
        return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, tableName);
    }

    /**
     * 列名转换成Java属性名
     */
    public static String columnToJava(String columnName) {
        return CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, columnName);
    }


    /**
     * 获取文件名
     */
    public static String getFileName(String template, String className, String packageName, String moduleName) {
        String packagePath = "main" + File.separator + "java" + File.separator;
        if (StringUtils.isNotBlank(packageName)) {
            packagePath += packageName.replace(".", File.separator)+ File.separator ;
        }

        if (template.contains("Entity.java.vm" )) {
            return packagePath + "entity" + File.separator + moduleName + File.separator + className + "Entity.java";
        }

        if (template.contains("Mapper.java.vm" )) {
            return packagePath + "dao" + File.separator + moduleName + File.separator + className + "Mapper.java";
        }
        if (template.contains("Mapper.xml.vm" )) {
            return packagePath + "dao" + File.separator + moduleName + File.separator + className + "Mapper.xml";
        }

        if (template.contains("Service.java.vm" )) {
            return packagePath + "service" + File.separator + moduleName + File.separator + className + "Service.java";
        }

        if (template.contains("ServiceImpl.java.vm" )) {
            return packagePath + "service" + File.separator  + moduleName + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
        }

        if (template.contains("Controller.java.vm" )) {
            return packagePath + "controller" + File.separator + moduleName + File.separator + className + "Controller.java";
        }


//        if (template.contains("index.vue.vm" )) {
//            return "main" + File.separator + "resources" + File.separator + "src" + File.separator + "views" + File.separator + "modules" +
//                    File.separator + moduleName + File.separator + className.toLowerCase() + ".vue";
//        }
//
//        if (template.contains("add-or-update.vue.vm" )) {
//            return "main" + File.separator + "resources" + File.separator + "src" + File.separator + "views" + File.separator + "modules" +
//                    File.separator + moduleName + File.separator + className.toLowerCase() + "-add-or-update.vue";
//        }

        return null;
    }
}
